package cn.edu.bupt.scidata.service.impl;

import cn.edu.bupt.scidata.mapper.Clf_clfMampper;
import cn.edu.bupt.scidata.mapper.Paper1Mapper;
import cn.edu.bupt.scidata.mapper.PaperMapper;
import cn.edu.bupt.scidata.model.paper.Paper;
import cn.edu.bupt.scidata.model.project.ElasticSearchProject;
import cn.edu.bupt.scidata.repository.ProjectRepository;
import cn.edu.bupt.scidata.service.PaperService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.lucene.search.function.FieldValueFactorFunction;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
public class PaperServiceImpl implements PaperService {
    @Autowired
    RestHighLevelClient client;
    @Autowired
    Paper1Mapper paper1Mapper;
    @Autowired
    Clf_clfMampper clf_clfMampper;

    @Autowired
    @Qualifier("myredisTemplate")
    RedisTemplate myredisTemplete;

    @Qualifier("projectRepository")
    private ProjectRepository projectRepository;

    @Override
    public List<Integer> queryPaperIds(int keyid) {
        String name = "keyid"+keyid;
        List<Integer> paperIdList = new ArrayList<>();
        if (myredisTemplete.opsForList().size(name)==0) {
            paperIdList = paper1Mapper.querypaperIdByWord(keyid);
            myredisTemplete.opsForList().rightPushAll(name, paperIdList);
        }else {
            long len=myredisTemplete.opsForList().size(name);
            paperIdList = myredisTemplete.opsForList().range(name,0,len-1);
        }
        return paperIdList;
    }

    @Autowired
    private PaperMapper paperMapper;
    @Override
    public List<Paper> querypaperpage(List<Integer> paperIds, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        return paperMapper.querypaperbykey(paperIds);
    }

    @Override
    public PageInfo<Paper> querypaperpagef(List<Integer> paperIds, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        List<Paper> lists = paperMapper.querypaperbykey(paperIds);
        return new PageInfo<>(lists);
    }

    @Override
    public List<Paper> querypaper(List<Integer> paperIds) {
        return paperMapper.querypaperbykey( paperIds);
    }
    @Override
    public List<ElasticSearchProject> search(int size, int page, String keyword) {
        Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "results", "_score");
        List<ElasticSearchProject> ret = new ArrayList<>();

        BoolQueryBuilder matchAllQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchPhraseQuery("keywords", keyword));
        BoolQueryBuilder matchAllQueryBuildertitle = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchPhraseQuery("title", keyword));

        projectRepository.search(matchAllQueryBuilder, pageable).forEach(ret::add);
        return ret;
    }
    @Override
    public Map<String,Object> subquery11(String clfname1, String key, Integer pageno, Integer pagesize, String order, String lang) throws IOException {

        String indice = "zcwpaper1";
        String matchField = "keywords";
        String clfname = clfname1;
        String clffield = "clf_name";
        QueryBuilder qb2;
        ExistsQueryBuilder existsQueryBuilder = QueryBuilders.existsQuery("time");
        if(Objects.equals(lang, "EN")){
            indice = "zcwenpaper";
            matchField = "cn_name";
            clfname = clf_clfMampper.selClfNoByName(clfname1);
            clffield = "classification";
            MatchPhraseQueryBuilder mpq1 = QueryBuilders
                    .matchPhraseQuery(clffield,clfname);
            MatchQueryBuilder mpq3 = QueryBuilders
                    .matchQuery(matchField,key);
            qb2 = QueryBuilders.boolQuery().must(existsQueryBuilder)
                    .must(mpq1)
                    .must(mpq3)
                    .should(QueryBuilders.rangeQuery("_score").from(100));;
        }else {
            MatchPhraseQueryBuilder mpq1 = QueryBuilders
                    .matchPhraseQuery(clffield,clfname);
            MatchQueryBuilder mpq3 = QueryBuilders
                    .matchQuery(matchField,key);
            MatchQueryBuilder mpq2 = QueryBuilders
                    .matchQuery("title",key);
            qb2 = QueryBuilders.boolQuery().must(existsQueryBuilder)
                    .must(mpq1)
                    .must(mpq3)
                    .must(mpq2)
                    .should(QueryBuilders.rangeQuery("_score").from(100));
        }

        SearchRequest searchRequest = new SearchRequest(indice);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        QueryBuilders.boolQuery()
//        MatchPhraseQueryBuilder mpq1 = QueryBuilders
//                .matchPhraseQuery(clffield,clfname);
//        MatchQueryBuilder mpq3 = QueryBuilders
//                .matchQuery(matchField,key);
////        MatchPhraseQueryBuilder mpq3 = QueryBuilders
////                .matchPhraseQuery("clf_name",clfname2);
//        QueryBuilder qb2 = QueryBuilders.boolQuery()
//                .must(mpq1)
//                .must(mpq3);
        if(Objects.equals(order, "zonghe")) {
            FieldValueFactorFunctionBuilder fieldQuery = new FieldValueFactorFunctionBuilder(
                    "time");
            fieldQuery.factor(0.0000000001f);
            fieldQuery.modifier(FieldValueFactorFunction.Modifier.NONE);

            FunctionScoreQueryBuilder functionScore = QueryBuilders
                    .functionScoreQuery(qb2, fieldQuery)
                    .boostMode(CombineFunction.SUM);
            sourceBuilder.query(functionScore);
        }else {
            sourceBuilder.query(qb2);
        }
//        AggregationBuilder aggregationBuilder =new AggregationBuilders()
//        sourceBuilder.aggregation()
        sourceBuilder.timeout(new TimeValue(6000, TimeUnit.SECONDS));
        String[] includeFields = new String[] {"title","time","author","quote","keywords","abstract"};
        if(!Objects.equals(order, "relate") && !Objects.equals(order, "zonghe")) {
            sourceBuilder.sort(new FieldSortBuilder(order).order(SortOrder.DESC));
        }else {
            sourceBuilder.sort(new FieldSortBuilder("_score").order(SortOrder.DESC));
        }
        String[] excludeFields = new String[] {};
        sourceBuilder.fetchSource(includeFields, excludeFields);
        sourceBuilder.from(pageno);
        sourceBuilder.size(pagesize);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse= client.search(searchRequest, RequestOptions.DEFAULT);
        searchResponse.getHits();
        List<Map<String,Object>> result=new ArrayList<Map<String, Object>>();
        for (SearchHit documentFields: searchResponse.getHits().getHits()){
            result.add(documentFields.getSourceAsMap());
        }
        int total= Math.toIntExact(searchResponse.getHits().getTotalHits());
        List<Map<String,Object>> pageinfo=new ArrayList<>();
        Map<String,Object> res=new HashMap<>();
        Map<String,Object> pa=new HashMap<>();
        res.put("list",result);
        res.put("pageNum",pageno);
        res.put("pageSize",pagesize);
        res.put("total",total);
        int totalpage= (int) Math.ceil(total / (double)pagesize);
        res.put("pages",totalpage);
        int[] arrayA;
        if (totalpage>8){
            arrayA = new int[8];
            for(int i=0;i<8;i++){
                arrayA[i]=i+1;
            }
//            arrayA = new int[]{1,2,3,4,5,6,7,8};
        }
        else {
            arrayA = new int[totalpage];
            for(int i=0;i<totalpage;i++){
                arrayA[i]=i+1;
            }
        }
        res.put("navigatepageNums",arrayA);
        if(pageno>1){
            res.put("hasPreviousPage",1);
        }
        else res.put("hasPreviousPage",0);
        if(pageno<totalpage){
            res.put("hasNextPage",1);
        }
        else res.put("hasNextPage",0);

        return res;
    }



}
